/*
 * Copyright (c) 2020 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "hiview_output_event.h"
// #include "securec.h"
#include "ohos_types.h"
#include "hiview_def.h"
#include "hiview_util.h"
#include "hiview_event.h"
#include "hiview_cache.h"
#include "hiview_config.h"
#include "hiview_log.h"
#include "hiview_file.h"
#include "hiview_service.h"

#define EVENT_PAYLOAD_MAX_SIZE   (5 * 16)

#ifdef SYNC_FILE
#undef SYNC_FILE
#endif
#define SYNC_FILE (1 << 6)

static HiviewCache g_faultEventCache = {
    .size = 0,
    .buffer = NULL,
};
static HiviewCache g_ueEventCache = {
    .size = 0,
    .buffer = NULL,
};
static HiviewCache g_statEventCache = {
    .size = 0,
    .buffer = NULL,
};
static HiviewFile g_faultEventFile = {
    .path = HIVIEW_FILE_PATH_FAULT_EVENT,
    .outPath = HIVIEW_FILE_OUT_PATH_FAULT_EVENT,
    .pFunc = NULL,
    .mutex = NULL,
    .fhandle = -1,
    .configSize = 0,
};
static HiviewFile g_ueEventFile = {
    .path = HIVIEW_FILE_PATH_UE_EVENT,
    .outPath = HIVIEW_FILE_OUT_PATH_UE_EVENT,
    .pFunc = NULL,
    .mutex = NULL,
    .fhandle = -1,
    .configSize = 0,
};
static HiviewFile g_statEventFile = {
    .path = HIVIEW_FILE_PATH_STAT_EVENT,
    .outPath = HIVIEW_FILE_OUT_PATH_STAT_EVENT,
    .pFunc = NULL,
    .mutex = NULL,
    .fhandle = -1,
    .configSize = 0,
};

typedef struct EventFlushInfo EventFlushInfo;
struct EventFlushInfo {
    HiviewMutexId_t mutex;
};
static EventFlushInfo g_eventFlushInfo;
static HieventProc g_hieventOutputProc = NULL;

typedef struct OutputEventInfo OutputEventInfo;
struct OutputEventInfo {
    HiviewMutexId_t mutex;
};
static OutputEventInfo g_outputEventInfo;

static int32 g_retryFaultInitCount = 0;
static int32 g_retryUeInitCount = 0;
static int32 g_retryStatInitCount = 0;
#define MAX_RETRY_COUNT 100

/* Output the event to UART using plaintext. */
static void OutputEventRealtime(const Request *req);
/* Output the event to FLASH using binary. */
static void OutputEvent2Flash(const Request *req);
static void InitFaultEventOutput(void);
static void InitUeEventOutput(void);
static void InitStatEventOutput(void);
static void Output2Flash(uint8 eventType);
static void CloseEventOutputFile(uint8 type);
static void GetEventCache(uint8 type, HiviewCache **c, HiviewFile **f);

void InitCoreEventOutput(void)
{
    g_eventFlushInfo.mutex = HIVIEW_MutexInit();
    g_outputEventInfo.mutex = HIVIEW_MutexInit();
    // HiviewRegisterMsgHandle(HIVIEW_MSG_OUTPUT_EVENT_BIN_FILE, OutputEvent2Flash);
    // HiviewRegisterMsgHandle(HIVIEW_MSG_OUTPUT_EVENT_FLOW, OutputEventRealtime);
}

void InitEventOutput(void)
{
    // InitFaultEventOutput();
    // InitUeEventOutput();
    // InitStatEventOutput();
}

void ClearEventOutput(void)
{
    // int8 opt = GETOPTION(g_hiviewConfig.outputOption);
    // if (opt == OUTPUT_OPTION_BIN_FILE || opt == OUTPUT_OPTION_TEXT_FILE) {
    //     CloseEventOutputFile(FAULT_EVENT_CACHE);
    //     CloseEventOutputFile(UE_EVENT_CACHE);
    //     CloseEventOutputFile(STAT_EVENT_CACHE);
    // }
}

static void InitFaultEventOutput(void)
{
    // int8 opt = GETOPTION(g_hiviewConfig.outputOption);
    // if (InitHiviewCache(&g_faultEventCache, FAULT_EVENT_CACHE, EVENT_CACHE_SIZE) == FALSE) {
    //     printf("malloc[%d] fail.", FAULT_EVENT_CACHE);
    // }
    // if (opt == OUTPUT_OPTION_DEBUG || opt == OUTPUT_OPTION_FLOW) {
    //     return;
    // }
    // if (InitHiviewFile(&g_faultEventFile, HIVIEW_FAULT_EVENT_FILE, FAULT_EVENT_FILE_SIZE) == FALSE) {
    //     printf("Open file[%d] failed.", HIVIEW_FAULT_EVENT_FILE);
    // }
    // g_faultEventFile.mutex = g_outputEventInfo.mutex;
}

static void InitUeEventOutput(void)
{
    // if (InitHiviewCache(&g_ueEventCache, UE_EVENT_CACHE, EVENT_CACHE_SIZE) == FALSE) {
    //     printf("malloc[%d] fail.", UE_EVENT_CACHE);
    // }
    // int8 opt = GETOPTION(g_hiviewConfig.outputOption);
    // if (opt == OUTPUT_OPTION_DEBUG || opt == OUTPUT_OPTION_FLOW) {
    //     return;
    // }
    // if (InitHiviewFile(&g_ueEventFile, HIVIEW_UE_EVENT_FILE, UE_EVENT_FILE_SIZE) == FALSE) {
    //     printf("Open file[%d] failed.", HIVIEW_UE_EVENT_FILE);
    // }
    // g_ueEventFile.mutex = g_outputEventInfo.mutex;
}

static void InitStatEventOutput(void)
{
    // if (InitHiviewCache(&g_statEventCache, STAT_EVENT_CACHE, EVENT_CACHE_SIZE) == FALSE) {
    //     printf("malloc[%d] fail.", STAT_EVENT_CACHE);
    // }
    // int8 opt = GETOPTION(g_hiviewConfig.outputOption);
    // if (opt == OUTPUT_OPTION_DEBUG || opt == OUTPUT_OPTION_FLOW) {
    //     return;
    // }
    // if (InitHiviewFile(&g_statEventFile, HIVIEW_STAT_EVENT_FILE, STAT_EVENT_FILE_SIZE) == FALSE) {
    //     printf("Open file[%d] failed.", HIVIEW_STAT_EVENT_FILE);
    // }
    // g_statEventFile.mutex = g_outputEventInfo.mutex;
}

static void CloseEventOutputFile(uint8 type)
{
    // HiviewCache *c = NULL;
    // HiviewFile *f = NULL;
    // GetEventCache(type, &c, &f);
    // if (c != NULL && c->usedSize > 0) {
    //     Output2Flash(type);
    // }
    // CloseHiviewFile(f);
}

static void ReInitHiEventFile(uint8 eventType)
{
    // if (eventType & HIEVENT_FAULT) {
    //     if (g_retryFaultInitCount > MAX_RETRY_COUNT) {
    //         return;
    //     }
    //     if (InitHiviewFile(&g_faultEventFile, HIVIEW_FAULT_EVENT_FILE, FAULT_EVENT_FILE_SIZE) == FALSE) {
    //         HILOG_ERROR(HILOG_MODULE_HIVIEW, "Open file[%d] failed.", HIVIEW_FAULT_EVENT_FILE);
    //         g_retryFaultInitCount++;
    //     } else {
    //         // once success, clean retry count
    //         g_retryFaultInitCount = 0;
    //     }
    // } else if (eventType & HIEVENT_UE) {
    //     if (g_retryUeInitCount > MAX_RETRY_COUNT) {
    //         return;
    //     }
    //     if (InitHiviewFile(&g_ueEventFile, HIVIEW_UE_EVENT_FILE, UE_EVENT_FILE_SIZE) == FALSE) {
    //         HILOG_ERROR(HILOG_MODULE_HIVIEW, "Open file[%d] failed.", HIVIEW_UE_EVENT_FILE);
    //         g_retryUeInitCount++;
    //     } else {
    //         // once success, clean retry count
    //         g_retryUeInitCount = 0;
    //     }
    // } else if (eventType & HIEVENT_STAT) {
    //     if (g_retryStatInitCount > MAX_RETRY_COUNT) {
    //         return;
    //     }
    //     if (InitHiviewFile(&g_statEventFile, HIVIEW_STAT_EVENT_FILE, STAT_EVENT_FILE_SIZE) == FALSE) {
    //         HILOG_ERROR(HILOG_MODULE_HIVIEW, "Open file[%d] failed.", HIVIEW_STAT_EVENT_FILE);
    //         g_retryStatInitCount++;
    //     } else {
    //         // once success, clean retry count
    //         g_retryStatInitCount = 0;
    //     }
    // }
}

void OutputEvent(const uint8 *data)
{
//     if (data == NULL) {
//         return;
//     }

//     if (g_hieventOutputProc != NULL && g_hieventOutputProc((HiEvent *)data) == TRUE) {
//         return;
//     }

//     HiEvent *event = (HiEvent *)data;
//     HiviewCache *c = NULL;
//     HiviewFile *f = NULL;
//     GetEventCache(event->type, &c, &f);
//     if (c == NULL) {
//         return;
//     }
// #if LITTLE_ENDIAN_SYSTEM
//     event->common.eventId = Change16Endian(event->common.eventId);
//     event->common.time = Change32Endian(event->common.time);
// #endif
//     boolean reachMaxThreshold  = FALSE;
//     /* If the cache reach the max size, output and do not write cache. */
//     if ((c->usedSize + sizeof(HiEventCommon) + event->common.len) > EVENT_CACHE_SIZE) {
//         HIVIEW_UartPrint("HiEvent have no sufficient space to write event info to cache!\n");
//         reachMaxThreshold = TRUE;
//     } else if (WriteToCache(c, (uint8 *)&(event->common), sizeof(HiEventCommon)) == sizeof(HiEventCommon)) {
//         WriteToCache(c, event->payload, event->common.len);
//     }

//     int8 opt = GETOPTION(g_hiviewConfig.outputOption);
//     if (c->usedSize >= HIVIEW_HIEVENT_FILE_BUF_SIZE || opt == OUTPUT_OPTION_DEBUG) {
//         switch (opt) {
//             /* Event do not support the text format */
//             case OUTPUT_OPTION_TEXT_FILE:
//             case OUTPUT_OPTION_BIN_FILE:
//                 HiviewSendMessage(HIVIEW_SERVICE, HIVIEW_MSG_OUTPUT_EVENT_BIN_FILE, event->type);
//                 break;
//             case OUTPUT_OPTION_FLOW:
//             case OUTPUT_OPTION_DEBUG:
//                 HiviewSendMessage(HIVIEW_SERVICE, HIVIEW_MSG_OUTPUT_EVENT_FLOW, event->type);
//                 break;
//             default:
//                 break;
//         }
//     }

//     /* The cache reach the max size, output and then write cache. */
//     if (reachMaxThreshold) {
//         if ((c->usedSize + sizeof(HiEventCommon) + event->common.len) > EVENT_CACHE_SIZE) {
//             if (WriteToCache(c, (uint8 *)&(event->common), sizeof(HiEventCommon)) == sizeof(HiEventCommon)) {
//                 WriteToCache(c, event->payload, event->common.len);
//             }
//         } else {
//             printf("HiEvent have no sufficient space to write, drop event id %d\n", event->common.eventId);
//         }
//     }
}

static void OutputEventRealtime(const Request *req)
{
//     HIVIEW_MutexLock(g_eventFlushInfo.mutex);
//     HiviewCache *c = NULL;
//     HiviewFile *f = NULL;
//     uint16 payloadLen;
//     HiEvent event;
//     uint8 payload[EVENT_PAYLOAD_MAX_SIZE];
//     char tmpBuffer[LOG_FMT_MAX_LEN] = {0};

//     event.type = (uint8)req->msgValue;
//     GetEventCache(event.type, &c, &f);
//     while (ReadFromCache(c, (uint8 *)&(event.common), sizeof(HiEventCommon)) == sizeof(HiEventCommon)) {
//         if (event.common.mark != EVENT_INFO_HEAD) {
//             DiscardCacheData(c);
//             printf("Discard cache[%d] data.", c->type);
//             break;
//         }
// #if LITTLE_ENDIAN_SYSTEM
//         event.common.eventId = Change16Endian(event.common.eventId);
//         event.common.time = Change32Endian(event.common.time);
// #endif
//         payloadLen = event.common.len;
//         if (payloadLen > sizeof(payload)) {
//             payloadLen = sizeof(payload);
//         }
//         if (payloadLen > 0 && ReadFromCache(c, payload, payloadLen) != payloadLen) {
//             break;
//         }
//         event.payload = (payloadLen > 0) ? payload : NULL;
//         EventContentFmt(tmpBuffer, LOG_FMT_MAX_LEN, (uint8 *)&event);
//         HIVIEW_UartPrint(tmpBuffer);
//     }
//     HIVIEW_MutexUnlock(g_eventFlushInfo.mutex);
}

static void OutputEvent2Flash(const Request *req)
{
    // Output2Flash((uint8)req->msgValue);
}

static void Output2Flash(uint8 eventType)
{
    // HIVIEW_MutexLock(g_eventFlushInfo.mutex);
    // HiviewCache *c = NULL;
    // HiviewFile *f = NULL;
    // uint8 *tmpBuffer = NULL;
    // HiEventCommon *pEventCommon = NULL;
    // uint16 len = 0, payloadLen, outputSize;

    // GetEventCache((uint8)eventType, &c, &f);
    // if (c == NULL) {
    //     HIVIEW_MutexUnlock(g_eventFlushInfo.mutex);
    //     return;
    // }
    // outputSize = c->usedSize;
    // if (outputSize < sizeof(HiEventCommon)) {
    //     HIVIEW_MutexUnlock(g_eventFlushInfo.mutex);
    //     return;
    // }
    // tmpBuffer = (uint8 *)HIVIEW_MemAlloc(MEM_POOL_HIVIEW_ID, outputSize);
    // if (tmpBuffer == NULL) {
    //     HIVIEW_MutexUnlock(g_eventFlushInfo.mutex);
    //     return;
    // }
    // while (c->usedSize >= sizeof(HiEventCommon) && outputSize >= (len + sizeof(HiEventCommon))) {
    //     if (ReadFromCache(c, tmpBuffer + len, sizeof(HiEventCommon)) != sizeof(HiEventCommon)) {
    //         continue;
    //     }
    //     pEventCommon = (HiEventCommon *)(tmpBuffer + len);
    //     len += sizeof(HiEventCommon);
    //     if (pEventCommon->mark != EVENT_INFO_HEAD) {
    //         DiscardCacheData(c);
    //         printf("Discard cache[%d] data.", c->type);
    //         break;
    //     }
    //     payloadLen = pEventCommon->len;
    //     if (payloadLen > 0) {
    //         if (ReadFromCache(c, tmpBuffer + len, payloadLen) != payloadLen) {
    //             continue;
    //         }
    //         len += payloadLen;
    //     }
    // }
    // if (f->fhandle < 0) {
    //     ReInitHiEventFile(eventType);
    // }
    // if (len > 0 && WriteToFile(f, tmpBuffer, len) != len) {
    //     g_hiviewConfig.writeFailureCount++;
    //     HIVIEW_UartPrint("Failed to write event data.");
    // }
    // HIVIEW_MemFree(MEM_POOL_HIVIEW_ID, tmpBuffer);
    // HIVIEW_MutexUnlock(g_eventFlushInfo.mutex);
    // if ((eventType & SYNC_FILE) != 0) {
    //     HIVIEW_FileSync(f->fhandle);
    // }
}

uint32 GetEventFileSize(uint8 eventType)
{
    // HiviewCache *c = NULL;
    // HiviewFile *f = NULL;

    // GetEventCache(eventType, &c, &f);
    // return GetFileUsedSize(f);
    return 0;
}

uint32 ReadEventFile(uint8 eventType, uint8 *buf, uint32 len)
{
    // HiviewCache *c = NULL;
    // HiviewFile *f = NULL;
    // uint32 usedSize;

    // if (buf == NULL) {
    //     return 0;
    // }
    // GetEventCache(eventType, &c, &f);
    // usedSize = GetFileUsedSize(f);
    // if (usedSize < len) {
    //     len = usedSize;
    // }
    // if (ReadFromFile(f, buf, len) != (int32)len) {
    //     return 0;
    // }

    // return len;
    return 0;
}

int32 EventContentFmt(char *outStr, int32 outStrLen, const uint8 *pEvent)
{
    // if (outStrLen < TAIL_LINE_BREAK) {
    //     return -1;
    // }
    // if (pEvent == NULL) {
    //     return -1;
    // }
    // int32 len;
    // uint32 time, hour, mte, sec;
    // HiEvent *event = (HiEvent *)pEvent;

    // time = event->common.time;
    // hour = time % SECONDS_PER_DAY / SECONDS_PER_HOUR;
    // mte = time % SECONDS_PER_HOUR / SECONDS_PER_MINUTE;
    // sec = time % SECONDS_PER_MINUTE;
    // if (event->payload == NULL) {
    //     len = snprintf_s(outStr, outStrLen, outStrLen - 1,
    //         "EVENT: time=%02d:%02d:%02d id=%d type=%d data=null",
    //         hour, mte, sec, event->common.eventId, event->type);
    // } else {
    //     len = snprintf_s(outStr, outStrLen, outStrLen - 1,
    //         "EVENT: time=%02d:%02d:%02d id=%d type=%d data=%p",
    //         hour, mte, sec, event->common.eventId, event->type, event->payload);
    // }

    // if (len < 0) {
    //     return -1;
    // }

    // if (len >= outStrLen - 1) {
    //     outStr[outStrLen - TAIL_LINE_BREAK] = '\n';
    //     outStr[outStrLen - 1] = '\0';
    // } else {
    //     outStr[len++] = '\n';
    //     outStr[len++] = '\0';
    // }

    // return len;
    return 0;
}

static void GetEventCache(uint8 type, HiviewCache **c, HiviewFile **f)
{
    // if (type & HIEVENT_FAULT) {
    //     *c = &g_faultEventCache;
    //     *f = &g_faultEventFile;
    // } else if (type & HIEVENT_UE) {
    //     *c = &g_ueEventCache;
    //     *f = &g_ueEventFile;
    // } else if (type & HIEVENT_STAT) {
    //     *c = &g_statEventCache;
    //     *f = &g_statEventFile;
    // } else {
    //     *c = NULL;
    //     *f = NULL;
    // }
}

static void FlushEventAsync(const uint8 type)
{
    // switch (GETOPTION(g_hiviewConfig.outputOption)) {
    //     /* Event do not support the text format */
    //     case OUTPUT_OPTION_TEXT_FILE:
    //     case OUTPUT_OPTION_BIN_FILE:
    //         HiviewSendMessage(HIVIEW_SERVICE, HIVIEW_MSG_OUTPUT_EVENT_BIN_FILE, type | SYNC_FILE);
    //         break;
    //     case OUTPUT_OPTION_FLOW:
    //         HiviewSendMessage(HIVIEW_SERVICE, HIVIEW_MSG_OUTPUT_EVENT_FLOW, type);
    //         break;
    //     default:
    //         break;
    // }
}

static void FlushEventInfo(const uint8 type, const HiviewCache *c, boolean syncFlag)
{
    // if (c == NULL) {
    //     return;
    // }
    // Request request = {0};
    // request.msgValue = type;
    // if (c->usedSize > 0) {
    //     if (syncFlag == FALSE) {
    //         /* If syncFlag is FALSE, refresh event information asynchronously */
    //         FlushEventAsync(type);
    //     } else {
    //         switch (GETOPTION(g_hiviewConfig.outputOption)) {
    //             /* Event do not support the text format */
    //             case OUTPUT_OPTION_TEXT_FILE:
    //             case OUTPUT_OPTION_BIN_FILE:
    //                 request.msgValue |= SYNC_FILE;
    //                 OutputEvent2Flash(&request);
    //                 break;
    //             case OUTPUT_OPTION_FLOW:
    //                 OutputEventRealtime(&request);
    //                 break;
    //             default:
    //                 break;
    //         }
    //     }
    // }
}

static void FlushFaultEvent(boolean syncFlag)
{
    // HiviewCache *c = NULL;
    // HiviewFile *f = NULL;

    // GetEventCache(HIEVENT_FAULT, &c, &f);
    // if (c == NULL || f == NULL) {
    //     return;
    // }
    // FlushEventInfo(HIEVENT_FAULT, c, syncFlag);
}

static void FlushUeEvent(boolean syncFlag)
{
    // HiviewCache *c = NULL;
    // HiviewFile *f = NULL;

    // GetEventCache(HIEVENT_UE, &c, &f);
    // if (c == NULL || f == NULL) {
    //     return;
    // }
    // FlushEventInfo(HIEVENT_UE, c, syncFlag);
}

static void FlushStatEvent(boolean syncFlag)
{
    // HiviewCache *c = NULL;
    // HiviewFile *f = NULL;

    // GetEventCache(HIEVENT_STAT, &c, &f);
    // if (c == NULL || f == NULL) {
    //     return;
    // }
    // FlushEventInfo(HIEVENT_STAT, c, syncFlag);
}

void FlushEvent(boolean syncFlag)
{
    // FlushFaultEvent(syncFlag);
    // FlushUeEvent(syncFlag);
    // FlushStatEvent(syncFlag);
}

void HiviewRegisterHieventProc(HieventProc func)
{
    g_hieventOutputProc = func;
}

void HiviewUnRegisterHieventProc(HieventProc func)
{
    (void)func;
    if (g_hieventOutputProc != NULL) {
        g_hieventOutputProc = NULL;
    }
}

int HiEventFileProcImp(uint8 type, const char *dest, uint8 mode)
{
    // Output2Flash(type);
    // HIVIEW_MutexLock(g_eventFlushInfo.mutex);
    // HiviewCache* c = NULL;
    // HiviewFile* f = NULL;

    // GetEventCache(type, &c, &f);
    // if (f == NULL || strcmp(f->path, dest) == 0) {
    //     HIVIEW_MutexUnlock(g_eventFlushInfo.mutex);
    //     return -1;
    // }
    // int ret = ProcFile(f, dest, (FileProcMode)mode);
    // HIVIEW_MutexUnlock(g_eventFlushInfo.mutex);
    // return ret;
    return 0;
}

void HiviewRegisterHieventFileWatcher(uint8 type, FileProc func, const char *path)
{
    // if (func == NULL) {
    //     return;
    // }
    // HiviewCache* c = NULL;
    // HiviewFile* f = NULL;
    // GetEventCache(type, &c, &f);
    // RegisterFileWatcher(f, func, path);
}

void HiviewUnRegisterHieventFileWatcher(uint8 type, FileProc func)
{
    // if (func == NULL) {
    //     return;
    // }
    // HiviewCache* c = NULL;
    // HiviewFile* f = NULL;
    // GetEventCache(type, &c, &f);
    // UnRegisterFileWatcher(f, func);
}

void HiEventOutputFileLockImp(void)
{
    HIVIEW_MutexLock(g_outputEventInfo.mutex);
}

void HiEventOutputFileUnLockImp(void)
{
    HIVIEW_MutexUnlock(g_outputEventInfo.mutex);
}
